package cn.virens.database.common.mapper;

import org.apache.ibatis.mapping.MappedStatement;

import tk.mybatis.mapper.entity.EntityColumn;
import tk.mybatis.mapper.mapperhelper.EntityHelper;
import tk.mybatis.mapper.mapperhelper.MapperHelper;
import tk.mybatis.mapper.mapperhelper.MapperTemplate;

public class ExampleJoinProvider extends MapperTemplate {

	public ExampleJoinProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
		super(mapperClass, mapperHelper);
	}

	/**
	 * 根据Example查询
	 *
	 * @param  ms MappedStatement
	 * @return    SQL
	 */
	public String selectJoin(MappedStatement ms) {
		Class<?> entityClass = getEntityClass(ms);
		String tableName = tableName(entityClass);

		//将返回值修改为实体类型
		setResultType(ms, entityClass);

		return buildSQL(entityClass, tableName);
	}

	/**
	 * 根据Example查询一条数据
	 *
	 * @param  ms MappedStatement
	 * @return    SQL
	 */
	public String selectJoinOne(MappedStatement ms) {
		return selectJoin(ms) + " LIMIT 1";
	}

	/**
	 * 根据Example查询
	 *
	 * @param  ms MappedStatement
	 * @return    SQL
	 */
	public String selectJoinMap(MappedStatement ms) {
		Class<?> entityClass = getEntityClass(ms);
		String tableName = tableName(entityClass);

		return buildSQL(entityClass, tableName);
	}

	/**
	 * 根据Example查询一条数据
	 *
	 * @param  ms MappedStatement
	 * @return    SQL
	 */
	public String selectJoinMapOne(MappedStatement ms) {
		return selectJoinMap(ms) + " LIMIT 1";
	}

	private String buildSQL(Class<?> entityClass, String tableName) {
		StringBuilder sql = new StringBuilder("SELECT \r\n");

		// 添加待查询列
		sql.append("<choose>\r\n");
		sql.append(" <when test=\"@tk.mybatis.mapper.util.OGNL@hasSelectColumns(_parameter)\">\r\n");
		sql.append("  <foreach collection=\"_parameter.selectColumns\" item=\"selectColumn\" separator=\",\">\r\n");
		sql.append("    ${selectColumn}\r\n");
		sql.append("  </foreach>\r\n");
		sql.append(" </when>\r\n");

		sql.append(" <otherwise>\r\n");
		for (EntityColumn entityColumn : EntityHelper.getColumns(entityClass)) {
			sql.append(tableName).append(".").append(entityColumn.getColumn()).append(",");
		}
		sql.deleteCharAt(sql.length() - 1);
		sql.append("\r\n");

		sql.append(" </otherwise>\r\n");
		sql.append("</choose>\r\n");

		// 添加待查询表
		sql.append(" FROM ").append(tableName).append("\r\n");

		// 添加外联查询
		sql.append("<foreach collection=\"_parameter.joinTables\" item=\"joinTable\">\r\n");
		sql.append(" ${joinTable.type} JOIN ${joinTable.table} ON ${joinTable.condition}\r\n");
		sql.append("</foreach>\r\n");

		// 添加查询条件
		sql.append("<where>\r\n");
		sql.append(" ${@tk.mybatis.mapper.util.OGNL@andNotLogicDelete(_parameter)}\r\n");
		sql.append(" <trim prefix=\"(\" prefixOverrides=\"and |or \" suffix=\")\">\r\n");
		sql.append("  <foreach collection=\"_parameter.oredCriteria\" item=\"criteria\">\r\n");
		sql.append("    <if test=\"criteria.valid\">\r\n");
		sql.append("      ${@tk.mybatis.mapper.util.OGNL@andOr(criteria)}");
		sql.append("      <trim prefix=\"(\" prefixOverrides=\"and |or \" suffix=\")\">\r\n");
		sql.append("        <foreach collection=\"criteria.criteria\" item=\"criterion\">\r\n");
		sql.append("          <choose>\r\n");
		sql.append("            <when test=\"criterion.noValue\">\r\n");
		sql.append("              ${@tk.mybatis.mapper.util.OGNL@andOr(criterion)} ${criterion.condition}\r\n");
		sql.append("            </when>\r\n");
		sql.append("            <when test=\"criterion.singleValue\">\r\n");
		sql.append("              ${@tk.mybatis.mapper.util.OGNL@andOr(criterion)} ${criterion.condition} #{criterion.value}\r\n");
		sql.append("            </when>\n");
		sql.append("            <when test=\"criterion.betweenValue\">\r\n");
		sql.append("              ${@tk.mybatis.mapper.util.OGNL@andOr(criterion)} ${criterion.condition} #{criterion.value} and #{criterion.secondValue}\r\n");
		sql.append("            </when>\r\n");
		sql.append("            <when test=\"criterion.listValue\">\r\n");
		sql.append("              ${@tk.mybatis.mapper.util.OGNL@andOr(criterion)} ${criterion.condition}\r\n");
		sql.append("              <foreach close=\")\" collection=\"criterion.value\" item=\"listItem\" open=\"(\" separator=\",\">\r\n");
		sql.append("                #{listItem}\r\n");
		sql.append("              </foreach>\r\n");
		sql.append("            </when>\r\n");
		sql.append("          </choose>\r\n");
		sql.append("        </foreach>\r\n");
		sql.append("      </trim>\r\n");
		sql.append("    </if>\r\n");
		sql.append("  </foreach>\r\n");
		sql.append(" </trim>\r\n");
		sql.append("</where>");

		// 添加分组规则
		sql.append("<if test=\"_parameter.groupByClause != null\">\r\n");
		sql.append("GROUP BY ${_parameter.groupByClause}\r\n");
		sql.append("</if>\r\n");

		// 添加Having查询
		sql.append("<if test=\"@cn.hutool.core.collection.CollUtil@isNotEmpty(_parameter.havings)\">\r\n");
		sql.append(" <trim prefix=\"HAVING \" prefixOverrides=\"AND |OR \" suffix=\"\">\r\n");
		sql.append("  <foreach collection=\"_parameter.havings\" item=\"havingItem\">\r\n");
		sql.append("   ${havingItem.type} ( ${havingItem.condition} ) \r\n");
		sql.append("  </foreach>\r\n");
		sql.append(" </trim>\r\n");
		sql.append("</if>\r\n");

		// 添加排序规则
		sql.append("<if test=\"_parameter.orderByClause != null\">\r\n");
		sql.append("ORDER BY ${_parameter.orderByClause}\r\n");
		sql.append("</if>\r\n");

		return sql.toString();
	}
}
